/*
 * Copyright (c) 2022 OpenLuat & AirM2M
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "bsp.h"
#include "bsp_custom.h"
#include "common_api.h"
#include "cJSON.h"
#include "audio_task.h"
#include "math.h"
#include "luat_rtos.h"
#include "luat_gpio.h"
#include "luat_mobile.h"
#include "luat_network_adapter.h"
#include "networkmgr.h"
#include "libemqtt.h"
#include "luat_mqtt.h"
#include "luat_debug.h"
#include "luat_pm.h"
#include "mqtt_task.h"
// #include "minimp3.h"
// #include "mp3_decode_port.h"
uint8_t g_s_is_link_up = 0;

luat_rtos_task_handle mqtt_publish_task_handle = NULL;
luat_rtos_task_handle mqtt_audio_state_handle = NULL;

static luat_rtos_task_handle mqtt_task_handle = NULL;
static luat_rtos_task_handle mqtt_config_task_handle = NULL;
static luat_rtos_task_handle socket_task_handle = NULL;
extern luat_rtos_queue_t audio_queue_handle;

extern bool audio_playing;

static luat_mqtt_ctrl_t *luat_mqtt_ctrl = NULL;
static luat_mqtt_ctrl_t *luat_mqtt_ctrl_config = NULL;

uint32_t cnt;
char *local_ip = NULL;

#define MQTT_HOST    	"150.158.45.48"   				// MQTT服务器的地址和端口号
#define MQTT_PORT		 1883

#define MQTT_SEND_BUFF_LEN       (1024)
#define MQTT_RECV_BUFF_LEN       (1024)

#define CLIENTID    "default"

#define IO_INPUT_PIN	HAL_GPIO_20
#define IO_CONTROL_PIN	HAL_GPIO_21

const static char mqtt_sub_topic_head[] = "api/v1/";    //订阅的主题头，待与设备imei进行拼接
static char topic_sub_audio[40];                            //订阅的主题，待存放订阅的主题头和设备imei，共计17+15,32个字符
static char topic_sub_audio_config[40];
static char topic_sub_io_control[40];
static char topic_sub_config[40];
static char topic_sub_login[40];
static char topic_pub_io_input[40];
static char topic_pub_configinfo[40];
static char topic_pub_status[40];
static char topic_pub_login[40];

static char mqtt_topic_1[] = "/mqtt_pub_topic_1";
static char mqtt_topic_2[] = "/mqtt_pub_topic_2";
static char mqtt_topic_3[] = "/mqtt_pub_topic_3";

int audio_queue_min = 50;
int audio_queue_max = 100;
bool io_in = false;

uint8_t get_net_status()
{
    return g_s_is_link_up;
}
uint8_t get_server_status()
{
    return luat_mqtt_ctrl->mqtt_state;
}

static void luat_mqtt_cb(luat_mqtt_ctrl_t *luat_mqtt_ctrl, uint16_t event){
	switch (event)
	{
	case MQTT_MSG_CONNACK:{
		LUAT_DEBUG_PRINT("mqtt_subscribe");
		uint16_t msgid = 0;
		if(1 == mqtt_subscribe(&(luat_mqtt_ctrl->broker), topic_sub_audio, &msgid, 1))
        {
            LUAT_DEBUG_PRINT("服务器连接成功");
        }
        mqtt_subscribe(&(luat_mqtt_ctrl->broker), topic_sub_audio_config, &msgid, 1);
        mqtt_subscribe(&(luat_mqtt_ctrl->broker), topic_sub_io_control, &msgid, 1);
        mqtt_subscribe(&(luat_mqtt_ctrl->broker), topic_sub_config, &msgid, 1);
        mqtt_subscribe(&(luat_mqtt_ctrl->broker), topic_sub_login, &msgid, 1);

        mqtt_publish_config();
        mqtt_publish_status();
		break;
	}
	case MQTT_MSG_PUBLISH : {
		const uint8_t* topic;
		uint16_t topic_len = mqtt_parse_pub_topic_ptr(luat_mqtt_ctrl->mqtt_packet_buffer, &topic);
        const uint8_t* payload;
		uint16_t payload_len = mqtt_parse_pub_msg_ptr(luat_mqtt_ctrl->mqtt_packet_buffer, &payload);
		// LUAT_DEBUG_PRINT("pub_topic: %.*s",topic_len, topic);
		// LUAT_DEBUG_PRINT("pub_msg: %.*s",payload_len, payload);
        led_control(1);
        if (strncmp(topic_sub_audio_config, topic, 34) == 0)
        {
            LUAT_DEBUG_PRINT("topic_sub_audio_config");

            cJSON *root = NULL;
            root = cJSON_Parse((const char *)payload);
            if (root == NULL)
            {
                LUAT_DEBUG_PRINT("topic_sub_audio_config cjson parse fail");
            }
            else
            {
                LUAT_DEBUG_PRINT("topic_sub_audio_config cjson parse success");
                cJSON *format = cJSON_GetObjectItem(root, "streamFormat");
                cJSON *rate = cJSON_GetObjectItem(root, "sampleRate");
                cJSON *volume = cJSON_GetObjectItem(root, "volume");
                cJSON *count = cJSON_GetObjectItem(root, "startCount");
                cJSON *queueMin = cJSON_GetObjectItem(root, "queueMin");
                cJSON *queueMax = cJSON_GetObjectItem(root, "queueMax");
                if (format != NULL && cJSON_IsNumber(format) &&
                    rate != NULL && cJSON_IsNumber(rate) &&
                    volume != NULL && cJSON_IsNumber(volume) &&
                    count != NULL && cJSON_IsNumber(count) &&
                    queueMin != NULL && cJSON_IsNumber(queueMin) &&
                    queueMax != NULL && cJSON_IsNumber(queueMax))
                {
                    audio_config((auStreamFormat_t)format->valueint, rate->valueint, volume->valueint, count->valueint);
                    luat_kv_set("streamFormat", format->valueint, sizeof(int));
                    luat_kv_set("sampleRate", rate->valueint, sizeof(int));
                    luat_kv_set("volume", volume->valueint, sizeof(int));
                    luat_kv_set("startCount", count->valueint, sizeof(int));
                    luat_kv_set("queueMin", queueMin->valueint, sizeof(int));
                    luat_kv_set("queueMax", queueMax->valueint, sizeof(int));

                    audio_queue_min = queueMin;
                    audio_queue_max = queueMax;
                    
                    LUAT_DEBUG_PRINT("streamFormat=%d, sampleRate=%d, volume=%d, startCount=%d, queueMin=%d, queueMax=%d", format->valueint, rate->valueint, volume->valueint, count->valueint, queueMin->valueint, queueMax->valueint);
                }
                else if (volume != NULL && cJSON_IsNumber(volume))
                {
                    audio_config(NULL, NULL, volume->valueint);
                    luat_kv_set("volume", volume->valueint, sizeof(int));
                    LUAT_DEBUG_PRINT("topic_sub_audio_config volume = %d", volume->valueint);
                }

                cJSON_Delete(root);
            }
        }
        else if (strncmp(topic_sub_audio, topic, 27) == 0)
        {
            audioQueueData queue = {0};
            queue.data = luat_heap_malloc(payload_len);
            memcpy(queue.data, payload, payload_len);
            queue.len = payload_len;

            if (-1 == luat_rtos_queue_send(audio_queue_handle, &queue, NULL, 300)){
                free(queue.data);
                LUAT_DEBUG_PRINT("cloud_speaker_mqtt sub queue send error");
            }
        }
        else if (strncmp(topic_sub_io_control, topic, 32) == 0)
        {
            LUAT_DEBUG_PRINT("topic_sub_io_control...");
            cJSON *root = NULL;
            root = cJSON_Parse((const char *)payload);
            if (root == NULL)
            {
                LUAT_DEBUG_PRINT("topic_sub_io_control cjson parse fail");
            }
            else
            {
                LUAT_DEBUG_PRINT("topic_sub_io_control cjson parse success");
                cJSON *io = cJSON_GetObjectItem(root, "io");
                if (io != NULL && cJSON_IsNumber(io))
                {
                    luat_gpio_set(IO_CONTROL_PIN, io->valueint);
                    LUAT_DEBUG_PRINT("topic_sub_io_control io = %d", io->valueint);
                }
                cJSON_Delete(root);
            }

        }
        else if (strncmp(topic_sub_login, topic, 27) == 0)
        {
            LUAT_DEBUG_PRINT("topic_sub_login and publish...");
            mqtt_publish_login();
        }
        else if (strncmp(topic_sub_config, topic, 28) == 0)
        {
            LUAT_DEBUG_PRINT("topic_sub_config...");
            cJSON *root = NULL;
            root = cJSON_Parse((const char *)payload);
            if (root == NULL)
            {
                LUAT_DEBUG_PRINT("topic_sub_config cjson parse fail");
            }
            else
            {
                LUAT_DEBUG_PRINT("topic_sub_config cjson parse success");
                cJSON *id = cJSON_GetObjectItem(root, "id");
                if(id != NULL && cJSON_IsString(id))
                {
                    luat_kv_set("id", id->valuestring, strlen(id->valuestring));
                }
                cJSON *ip = cJSON_GetObjectItem(root, "ip");
                if(ip != NULL && cJSON_IsString(ip))
                {
                    luat_kv_set("ip", ip->valuestring, strlen(ip->valuestring));
                }
                mqtt_publish_config();

                cJSON_Delete(root);
            }

            luat_rtos_task_sleep(1000);
            luat_pm_reboot();
        }
		break;
	}
	case MQTT_MSG_PUBACK :
	case MQTT_MSG_PUBCOMP : {
		LUAT_DEBUG_PRINT("msg_id: %d",mqtt_parse_msg_id(luat_mqtt_ctrl->mqtt_packet_buffer));
		break;
	}
	default:
		break;
	}
	return;
}

static void luat_mqtt_config_cb(luat_mqtt_ctrl_t *luat_mqtt_ctrl, uint16_t event){
	switch (event)
	{
	case MQTT_MSG_CONNACK:{
		LUAT_DEBUG_PRINT("mqtt_config_subscribe");
		uint16_t msgid = 0;
        if(1 == mqtt_subscribe(&(luat_mqtt_ctrl->broker), topic_sub_config, &msgid, 1))
        {
            LUAT_DEBUG_PRINT("配置服务器连接成功");
        }

        mqtt_publish_config();
		break;
	}
	case MQTT_MSG_PUBLISH : {
		const uint8_t* topic;
		uint16_t topic_len = mqtt_parse_pub_topic_ptr(luat_mqtt_ctrl->mqtt_packet_buffer, &topic);
        const uint8_t* payload;
		uint16_t payload_len = mqtt_parse_pub_msg_ptr(luat_mqtt_ctrl->mqtt_packet_buffer, &payload);
		// LUAT_DEBUG_PRINT("pub_topic: %.*s",topic_len, topic);
		// LUAT_DEBUG_PRINT("pub_msg: %.*s",payload_len, payload);
        if (strncmp(topic_sub_config, topic, 28) == 0)
        {
            LUAT_DEBUG_PRINT("topic_sub_config...");
            cJSON *root = NULL;
            root = cJSON_Parse((const char *)payload);
            if (root == NULL)
            {
                LUAT_DEBUG_PRINT("topic_sub_config cjson parse fail");
            }
            else
            {
                LUAT_DEBUG_PRINT("topic_sub_config cjson parse success");
                cJSON *id = cJSON_GetObjectItem(root, "id");
                if(id != NULL && cJSON_IsString(id))
                {
                    luat_kv_set("id", id->valuestring, strlen(id->valuestring));
                }
                cJSON *ip = cJSON_GetObjectItem(root, "ip");
                if(ip != NULL && cJSON_IsString(ip))
                {
                    luat_kv_set("ip", ip->valuestring, strlen(ip->valuestring));
                }
                mqtt_publish_config();
            }
            cJSON_Delete(root);

            luat_rtos_task_sleep(1000);
            LUAT_DEBUG_PRINT("配置成功，设备重启中...");
            luat_pm_reboot();
        }
		break;
	}
	case MQTT_MSG_PUBACK :
	case MQTT_MSG_PUBCOMP : {
		LUAT_DEBUG_PRINT("msg_id: %d",mqtt_parse_msg_id(luat_mqtt_ctrl->mqtt_packet_buffer));
		break;
	}
	default:
		break;
	}
	return;
}

void mqtt_publish_config()
{
        cJSON *root = cJSON_CreateObject();
        char imei[17] = {0};
        luat_kv_get("imei", imei, 17);
	    cJSON_AddItemToObject(root, "imei", cJSON_CreateString(&imei));
        char id[40] = {0};
        luat_kv_get("id", id, 40);
	    cJSON_AddItemToObject(root, "id", cJSON_CreateString(&id));
        char ip[16] = {0};
        luat_kv_get("ip", ip, 16);
	    cJSON_AddItemToObject(root, "ip", cJSON_CreateString(&ip));

        char *msg = cJSON_Print(root);
        mqtt_publish_with_qos(&(luat_mqtt_ctrl_config->broker), topic_pub_configinfo, msg, strlen(msg), 1, 2, NULL);

        cJSON_Delete(root);
        free(msg);
}

void mqtt_publish_status()
{
    led_control(1);
    cJSON *root = cJSON_CreateObject();
    char id[40] = {0};
    char csq;
    luat_kv_get("id", id, 40);
    luat_mobile_get_last_notify_signal_strength(&csq);

    cJSON_AddItemToObject(root, "id", cJSON_CreateString(&id));
    cJSON_AddItemToObject(root, "task", cJSON_CreateNumber(audio_playing ? 1 : 0));
    cJSON_AddItemToObject(root, "csq", cJSON_CreateNumber(csq));
    cJSON_AddItemToObject(root, "queue", cJSON_CreateNumber(cnt));

    char *msg = cJSON_Print(root);
    mqtt_publish_with_qos(&(luat_mqtt_ctrl->broker), topic_pub_status, msg, strlen(msg), 0, 0, NULL);

    cJSON_Delete(root);
    free(msg);
}

void mqtt_publish_login()
{
    led_control(1);
    cJSON *root = cJSON_CreateObject();
    char id[40] = {0};
    luat_kv_get("id", id, 40);
    cJSON_AddItemToObject(root, "id", cJSON_CreateString(&id));
    cJSON_AddItemToObject(root, "ip", cJSON_CreateString(local_ip));
    char imei[17] = {0};
    luat_kv_get("imei", imei, 17);
    cJSON_AddItemToObject(root, "imei", cJSON_CreateString(&imei));
    cJSON_AddItemToObject(root, "login", cJSON_CreateNumber(1));

    char *msg = cJSON_Print(root);
    mqtt_publish_with_qos(&(luat_mqtt_ctrl->broker), topic_pub_login, msg, strlen(msg), 0, 0, NULL);

    cJSON_Delete(root);
    free(msg);
}

void mqtt_publish_io()
{
    cJSON *root = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "pin", cJSON_CreateNumber(IO_INPUT_PIN));
    cJSON_AddItemToObject(root, "status", cJSON_CreateNumber(0));

    char *msg = cJSON_Print(root);
    mqtt_publish_with_qos(&(luat_mqtt_ctrl->broker), topic_pub_io_input, msg, strlen(msg), 0, 0, NULL);

    cJSON_Delete(root);
    free(msg);
}

static void luat_mqtt_config_task(void *param)
{
	int ret = -1;
    luat_mqtt_ctrl_config = (luat_mqtt_ctrl_t *)luat_heap_malloc(sizeof(luat_mqtt_ctrl_t));
	ret = luat_mqtt_init(luat_mqtt_ctrl_config, NW_ADAPTER_INDEX_LWIP_GPRS);
	if (ret) {
		LUAT_DEBUG_PRINT("mqtt_config init FAID ret %d", ret);
		return 0;
	}
    luat_mqtt_ctrl_config->ip_addr.type = 0xff;
	luat_mqtt_connopts_t opts = {0};
    opts.is_tls = 0;
    opts.host = MQTT_HOST;
	opts.port = MQTT_PORT;
	ret = luat_mqtt_set_connopts(luat_mqtt_ctrl_config, &opts);

    char config[32] = "cfg_";
    char clientId[17] = {0};
    ret = luat_kv_get("imei", clientId, 17);             //从数据库中读取clientId
    if(ret > 0 )
    {
        strcat(config, clientId);
        mqtt_init(&(luat_mqtt_ctrl_config->broker), config);
    }
    else                                                //数据库中没有写入过clientId，获取设
    {
        int result = 0;
        result = luat_mobile_get_imei(0, clientId, 15); //imei是15位，留一个位置放0x00
        if(result <= 0)
        {
            strcat(config, CLIENTID);
            mqtt_init(&(luat_mqtt_ctrl_config->broker), config);
            LUAT_DEBUG_PRINT("cloud_speaker_mqtt clientid config get fail");
        }
        else
        {
            luat_kv_set("imei", clientId, strlen(clientId));
            strcat(config, clientId);
            mqtt_init(&(luat_mqtt_ctrl_config->broker), config);
            LUAT_DEBUG_PRINT("cloud_speaker_mqtt clientid config get success %s", config);
        }
    }

    memset(topic_sub_config, 0x00, sizeof(topic_sub_config));
    snprintf(topic_sub_config, 40, "%s%s%s", mqtt_sub_topic_head, "config/", config);
    LUAT_DEBUG_PRINT("cloud_speaker_mqtt subscribe_topic %s %s", topic_sub_config, config);

    memset(topic_pub_configinfo, 0x00, sizeof(topic_pub_configinfo));
    snprintf(topic_pub_configinfo, 40, "%s%s%s", mqtt_sub_topic_head, "configinfo/", config);
    LUAT_DEBUG_PRINT("cloud_speaker_mqtt publish %s %s", topic_pub_configinfo, config);

    mqtt_init_auth(&(luat_mqtt_ctrl_config->broker), NULL, NULL);

    luat_mqtt_set_will(&(luat_mqtt_ctrl_config->broker), topic_pub_configinfo, NULL, 0, 2, 1);

    luat_mqtt_ctrl_config->broker.clean_session = 1;
	luat_mqtt_ctrl_config->keepalive = 30;

	luat_mqtt_ctrl_config->reconnect = 1;
	luat_mqtt_ctrl_config->reconnect_time = 3000;

	luat_mqtt_set_cb(luat_mqtt_ctrl_config,luat_mqtt_config_cb);

	luat_rtos_task_sleep(3000);
	LUAT_DEBUG_PRINT("mqtt_config_connect");
	ret = luat_mqtt_connect(luat_mqtt_ctrl_config);
	if (ret) {
		LUAT_DEBUG_PRINT("mqtt config connect ret=%d\n", ret);
		luat_mqtt_close_socket(luat_mqtt_ctrl_config);
		return;
	}
	LUAT_DEBUG_PRINT("mqtt_config_connect ok");
    while (1)
    {
        if (io_in)
        {
            io_in = false;

            mqtt_publish_io();
        }
        luat_rtos_task_sleep(100);
    }

}

static void luat_mqtt_task(void *param)
{
	int ret = -1;
	luat_mqtt_ctrl = (luat_mqtt_ctrl_t *)luat_heap_malloc(sizeof(luat_mqtt_ctrl_t));
	ret = luat_mqtt_init(luat_mqtt_ctrl, NW_ADAPTER_INDEX_LWIP_GPRS);
	if (ret) {
		LUAT_DEBUG_PRINT("mqtt init FAID ret %d", ret);
		return 0;
	}
	luat_mqtt_ctrl->ip_addr.type = 0xff;
	luat_mqtt_connopts_t opts = {0};

#if (MQTT_DEMO_SSL == 1)
	opts.is_tls = 1;
	opts.server_cert = testCaCrt;
	opts.server_cert_len = strlen(testCaCrt);
	opts.client_cert = testclientCert;
	opts.client_cert_len = strlen(testclientCert);
	opts.client_key = testclientPk;
	opts.client_key_len = strlen(testclientPk);
#else
	opts.is_tls = 0;
#endif
    char str[32] = {0};
    char ip[17] = {0};
    char clientId[17] = {0};
    char username[17] = {0};
    char password[17] = {0};
    ret = luat_kv_get("ip", ip, 17);
    if(ret > 0 )
    {
        memcpy(clientId, ip, 16);
    }
	opts.host = ip;
	opts.port = MQTT_PORT;

    ret = luat_mqtt_set_connopts(luat_mqtt_ctrl, &opts);

    ret = luat_kv_get("imei", str, 17);             //从数据库中读取clientId
    if(ret > 0 )
    {
        memcpy(clientId, str, 16);                      //留一位确保字符串结尾能有0x00
        mqtt_init(&(luat_mqtt_ctrl->broker), clientId);
    }
    else                                                //数据库中没有写入过clientId，获取设
    {
        int result = 0;
        result = luat_mobile_get_imei(0, clientId, 15); //imei是15位，留一个位置放0x00
        if(result <= 0)
        {
            mqtt_init(&(luat_mqtt_ctrl->broker), CLIENTID);
            LUAT_DEBUG_PRINT("cloud_speaker_mqtt clientid get fail");
        }
        else
        {
            luat_kv_set("imei", clientId, strlen(clientId));
            mqtt_init(&(luat_mqtt_ctrl->broker), clientId);
            LUAT_DEBUG_PRINT("cloud_speaker_mqtt clientid get success %s", clientId);
        }
    }
    memset(str, 0, 32);
    ret = luat_kv_get("username", str, 17);             //从数据库中读取username，如果没读到
    if(ret > 0 )
    {
        memcpy(username, str, 16);                      //留一位确保字符串结尾能有0x00
        // connectData.username.cstring = username;
    }
    memset(str, 0, 32);
    ret = luat_kv_get("password", str, 17);             //从数据库中读取password，如果没读到
    if(ret > 0 )
    {
        memcpy(password, str, 16);                      //留一位确保字符串结尾能有0x00
        // connectData.password.cstring = password;
    }

    memset(topic_sub_audio, 0x00, sizeof(topic_sub_audio));
    snprintf(topic_sub_audio, 40, "%s%s%s", mqtt_sub_topic_head, "audio/", clientId);
    LUAT_DEBUG_PRINT("cloud_speaker_mqtt subscribe_topic %s %s %s %s", topic_sub_audio, clientId, username, password);

    memset(topic_sub_audio_config, 0x00, sizeof(topic_sub_audio_config));
    snprintf(topic_sub_audio_config, 40, "%s%s%s", mqtt_sub_topic_head, "audio/config/", clientId);
    LUAT_DEBUG_PRINT("cloud_speaker_mqtt subscribe_topic %s %s %s %s", topic_sub_audio_config, clientId, username, password);

    memset(topic_sub_io_control, 0x00, sizeof(topic_sub_io_control));
    snprintf(topic_sub_io_control, 40, "%s%s%s", mqtt_sub_topic_head, "io/control/", clientId);
    LUAT_DEBUG_PRINT("cloud_speaker_mqtt subscribe_topic %s %s %s %s", topic_sub_io_control, clientId, username, password);

    memset(topic_sub_login, 0x00, sizeof(topic_sub_login));
    snprintf(topic_sub_login, 40, "%s%s%s", mqtt_sub_topic_head, "login/", clientId);
    LUAT_DEBUG_PRINT("cloud_speaker_mqtt subscribe_topic %s %s %s %s", topic_sub_login, clientId, username, password);

    memset(topic_pub_io_input, 0x00, sizeof(topic_pub_io_input));
    snprintf(topic_pub_io_input, 40, "%s%s%s", mqtt_sub_topic_head, "io/input/", clientId);
    LUAT_DEBUG_PRINT("cloud_speaker_mqtt publish %s %s %s %s", topic_pub_io_input, clientId, username, password);

    memset(topic_pub_status, 0x00, sizeof(topic_pub_status));
    snprintf(topic_pub_status, 40, "%s%s%s", mqtt_sub_topic_head, "status/", clientId);
    LUAT_DEBUG_PRINT("cloud_speaker_mqtt publish %s %s %s %s", topic_pub_status, clientId, username, password);

    memset(topic_pub_login, 0x00, sizeof(topic_pub_login));
    snprintf(topic_pub_login, 40, "%s%s%s", mqtt_sub_topic_head, "login/", "000000000000000");
    LUAT_DEBUG_PRINT("cloud_speaker_mqtt publish %s %s %s %s", topic_pub_login, clientId, username, password);

	mqtt_init_auth(&(luat_mqtt_ctrl->broker), username, password);

    // luat_mqtt_set_will(&(luat_mqtt_ctrl->broker), topic_pub_configinfo, NULL, 0, 2, 1);

	// luat_mqtt_ctrl->netc->is_debug = 1;// debug信息
	luat_mqtt_ctrl->broker.clean_session = 1;
	luat_mqtt_ctrl->keepalive = 30;

	luat_mqtt_ctrl->reconnect = 1;
	luat_mqtt_ctrl->reconnect_time = 3000;

	luat_mqtt_set_cb(luat_mqtt_ctrl,luat_mqtt_cb);

	luat_rtos_task_sleep(3000);
	LUAT_DEBUG_PRINT("mqtt_connect");
	ret = luat_mqtt_connect(luat_mqtt_ctrl);
	if (ret) {
		LUAT_DEBUG_PRINT("mqtt connect ret=%d\n", ret);
		luat_mqtt_close_socket(luat_mqtt_ctrl);
		return;
	}
	LUAT_DEBUG_PRINT("mqtt_connect ok");

	while(1){
        LUAT_DEBUG_PRINT("get_server_status link status %d, %d", get_server_status(), get_net_status());

        size_t total, used, max_used;
        luat_meminfo_sys(&total, &used, &max_used);
        LUAT_DEBUG_PRINT("meminfo total %d, used %d, max_used%d",total, used, max_used);

        if (1 == get_server_status() && 1 == get_net_status())
        {
            mqtt_publish_status();
        }

		luat_rtos_task_sleep(5000);
	}
}

static void luatos_mobile_event_callback(LUAT_MOBILE_EVENT_E event, uint8_t index, uint8_t status)
{
	if (LUAT_MOBILE_EVENT_NETIF == event)
	{
		if (LUAT_MOBILE_NETIF_LINK_ON == status)
		{
            g_s_is_link_up = 1;
			ip_addr_t dns_ip[2];
			uint8_t type, dns_num;
			dns_num = 2;
			soc_mobile_get_default_pdp_part_info(&type, NULL, NULL, &dns_num, dns_ip);

			if (type & 0x80)
			{
				if (index != 4)
				{
					return;
				}
				else
				{
					NmAtiNetifInfo *pNetifInfo = malloc(sizeof(NmAtiNetifInfo));
					NetMgrGetNetInfo(0xff, pNetifInfo);
					if (pNetifInfo->ipv6Cid != 0xff)
					{
						net_lwip_set_local_ip6(&pNetifInfo->ipv6Info.ipv6Addr);
					}
					free(pNetifInfo);
				}
			}
			if (dns_num > 0)
			{
				network_set_dns_server(NW_ADAPTER_INDEX_LWIP_GPRS, 2, &dns_ip[0]);
				if (dns_num > 1)
				{
					network_set_dns_server(NW_ADAPTER_INDEX_LWIP_GPRS, 3, &dns_ip[1]);
				}
			}
			net_lwip_set_link_state(NW_ADAPTER_INDEX_LWIP_GPRS, 1);
            ip_addr_t ipv4, ipv6;
            luat_mobile_get_local_ip(0, 1, &ipv4, &ipv6);
			if (ipv4.type != 0xff)
			{
                local_ip =ip4addr_ntoa(&ipv4.u_addr.ip4);
				LUAT_DEBUG_PRINT("local IPV4 = %s", ip4addr_ntoa(&ipv4.u_addr.ip4));
			}
		}
        else if(LUAT_MOBILE_NETIF_LINK_OFF == status || LUAT_MOBILE_NETIF_LINK_OOS == status)
        {
            g_s_is_link_up = 0;
        }
	}
}

static void luat_mqtt_publish_task(void *args)
{
    uint32_t id = 0;
    bool audio_playing;
	while(1)
	{
		if(0 == luat_rtos_message_recv(mqtt_publish_task_handle, &id, &audio_playing, LUAT_WAIT_FOREVER))
		{
            mqtt_publish_status();
            LUAT_DEBUG_PRINT("status changed audio_playing = %d", audio_playing);
        }
        luat_rtos_task_sleep(10);
	}
}

static void luat_mqtt_audio_state_task(void *args)
{
    // luat_debug_set_fault_mode(LUAT_DEBUG_FAULT_HANG);
    while (1)
    {
        luat_rtos_queue_get_cnt(audio_queue_handle, &cnt);
        if (audio_playing && (cnt > audio_queue_max  || cnt < audio_queue_min))
        {
            mqtt_publish_status();
            LUAT_DEBUG_PRINT("luat_rtos_queue_get_cnt ----------- cnt = %d", cnt);
        }

        luat_rtos_task_sleep(1000);
    }
}

static void luat_libemqtt_init(void)
{
	luat_mobile_event_register_handler(luatos_mobile_event_callback);
	net_lwip_init();
	net_lwip_register_adapter(NW_ADAPTER_INDEX_LWIP_GPRS);
	network_register_set_default(NW_ADAPTER_INDEX_LWIP_GPRS);
    luat_rtos_task_create(&mqtt_config_task_handle, 2 * 1024, 30, "libemqtt_config", luat_mqtt_config_task, NULL, 16);
	luat_rtos_task_create(&mqtt_task_handle, 2 * 1024, 40, "libemqtt", luat_mqtt_task, NULL, 16);
    luat_rtos_task_create(&mqtt_publish_task_handle, 2 * 1024, 20, "libemqtt pulish task", luat_mqtt_publish_task, NULL, 16);
    luat_rtos_task_create(&mqtt_audio_state_handle, 2 * 1024, 20, "libemqtt state task", luat_mqtt_audio_state_task, NULL, 16);
}

int gpio_irq(int pin, void* args)
{
	if (pin == IO_INPUT_PIN)
	{
        io_in = true;
	}

	//注意：中断服务程序中的一行LUAT_DEBUG_PRINT日志，如果通过Luatools查看，最多仅支持64字节
	LUAT_DEBUG_PRINT("pin:%d, level:%d,", pin, luat_gpio_get(pin));
}

static void io_init(void)
{
	luat_gpio_cfg_t gpio_cfg;
	luat_gpio_set_default_cfg(&gpio_cfg);

	// gpio_cfg.pull = LUAT_GPIO_DEFAULT;
    // gpio_cfg.mode = LUAT_GPIO_OUTPUT;
    gpio_cfg.pin = IO_CONTROL_PIN;
	luat_gpio_open(&gpio_cfg);

    luat_gpio_set_default_cfg(&gpio_cfg);
    gpio_cfg.pin = IO_INPUT_PIN;
    gpio_cfg.mode = LUAT_GPIO_IRQ;

	gpio_cfg.irq_type = LUAT_GPIO_FALLING_IRQ;

	gpio_cfg.pull = LUAT_GPIO_PULLUP;
	gpio_cfg.irq_cb = gpio_irq;
	luat_gpio_open(&gpio_cfg);
}

extern void fdb_init(void);
extern void led_control(int level);
extern void led_task_init(void);
extern void audio_config(auStreamFormat_t format, int rate, int volume);
extern void socket_task_init(void);

INIT_HW_EXPORT(fdb_init, "1");
INIT_TASK_EXPORT(luat_libemqtt_init, "1");
INIT_TASK_EXPORT(io_init, "1");
INIT_TASK_EXPORT(audio_task_init, "2");
INIT_TASK_EXPORT(led_task_init, "2");
INIT_TASK_EXPORT(socket_task_init, "2");

